package adke.managers;

import adke.Main;
import adke.debug.DebugActionManager;
import adke.gui.Overview;
import adke.models.ControlSet;
import adke.models.Player;
import adke.models.powerups.Powerup;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.util.Vector;

// deze importeren we static op deze manier zodat we de VK_KEYS statisch kunnen gebruiken
import static java.awt.event.KeyEvent.*;

// houd bij wie welke knoppen heeft toegewezen

public class InputManager implements KeyEventDispatcher
{
    // layout
    public final static int LEFT =      0; 
    public final static int MIDDLE =    1;
    public final static int RIGHT =     2; // bij numpad enzo
        
    // net als het origineel gebrbuiken we spatie om door schermen te komen
    public final static int SYSTEM_KEY = VK_SPACE;
    public final static int QUIT_KEY = VK_ESCAPE;
    public final static int DEBUG_KEY = VK_F1;
    
    // sommige knoppen zijn niet te gebruiken
    // dit zijn de zogeheten 'modifiers'.
    // deze knoppen zoals ALT, SHIFT en CTRL
    // worden door de keylisteners pas geregistreerd als
    // ze worden losgelaten
    
    // key combinaties
    // de eerste in elke array is de LINKS knop
    // de tweede is de POWER knop
    // de derde is RECHTS
    public final static ControlSet[] CONTROL_SETS = new ControlSet[]
    {
        // zie static import
        // zie static import
        new ControlSet(VK_Z, VK_X, VK_C),    
//        new ControlSet(VK_V, VK_B, VK_N),
        new ControlSet(VK_M, VK_COMMA, VK_PERIOD),
//        new ControlSet(VK_A, VK_S, VK_D),
//        new ControlSet(VK_F, VK_G, VK_H),
//        new ControlSet(VK_J, VK_K, VK_L),
        new ControlSet(VK_Q, VK_W, VK_E),
//        new ControlSet(VK_R, VK_T, VK_Y),
//        new ControlSet(VK_U, VK_I, VK_O),
        new ControlSet(VK_P, VK_OPEN_BRACKET, VK_CLOSE_BRACKET)
    };

    private static Vector<ControlSet> controls;
    
    public InputManager()
    {
        controls = new Vector();
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher (this);
    }
    
    public static ControlSet generateControls(ControlSet oldControls)
    {
        returnControls(oldControls);
        ControlSet newSet = null;
        for (int i = 0; i < CONTROL_SETS.length && !validateControls(newSet); i++)
        {
            newSet = CONTROL_SETS[i];
        }
        controls.add(newSet);
        return newSet;
    }
    
    private static boolean validateControls(ControlSet set)
    {
        return !controls.contains(set) && set != null;
    }
    
    public static void returnControls(ControlSet set)
    {
        controls.remove(set);
    }
    
    // TODO: deze moet nog kijken of er extra muizen zijn aangesloten etc
    public static int getMaximumInputs()
    {
        return CONTROL_SETS.length;
    }
    
    // kijkt of dit een power key is voor een van de controlsets die zijn
    // geregistreerd
    public static boolean isPowerKey(int key)
    {
        return getControlsWithPowerKey(key) != null;
    }
    
    public static boolean isLeftKey(int key)
    {
        return getControlsWithLeftKey(key) != null;
    }
    
    public static boolean isRightKey(int key)
    {
        return getControlsWithRightKey(key) != null;
    }
    
    public static ControlSet getControlsWithLeftKey(int key)
    {
        for (ControlSet set : CONTROL_SETS)
        {
            int pwrkey = set.getLeftKey();
            if (pwrkey == key)
            {
                return set;
            }
        }
        
        return null;
    }
    
    public static ControlSet getControlsWithRightKey(int key)
    {
        for (ControlSet set : CONTROL_SETS)
        {
            int pwrkey = set.getRightKey();
            if (pwrkey == key)
            {
                return set;
            }
        }
        
        return null;
    }
    
    public static ControlSet getControlsWithPowerKey(int key)
    {
        for (ControlSet set : CONTROL_SETS)
        {
            int pwrkey = set.getPowerKey();
            if (pwrkey == key)
            {
                return set;
            }
        }
        
        return null;
    }

    // inputs
    public static boolean isQuitKey(int key)
    {
        return key == QUIT_KEY;
    }
    
    public static boolean isSystemKey(int key)
    {
        return key == SYSTEM_KEY;
    }
    
    public static boolean isDebugKey(int key)
    {
        return key == DEBUG_KEY;
    }
    
    // opsplitsing van de dispatchevent
    private static void setupState(KeyEvent e)
    {
        int key = e.getKeyCode();
        
        if (key == SYSTEM_KEY)
        {
            GameManager.startGame();
        }
        
        else if (key == VK_ENTER && e.getID() == e.KEY_RELEASED)
        {
            Overview.getInstance().getSetupPanel().addPlayer();
        }
        
        else
        {
            // als hij tot hier komt is er misschien wel een powerknop ingedrukt
            boolean isPowerKey = InputManager.isPowerKey(key);

            // als er een powerknop is ingedrukt moeten we kijken welke player dat heeft gedaan
            if (isPowerKey)
            {
                ControlSet set = InputManager.getControlsWithPowerKey(key);

                // nu weten we welke player er op de powerknop heeft gedrukt
                Player player = set.getOwner();

                // nu moeten we de player verwijderen uit de lijst
                PlayerManager.removePlayer(player);

                Overview.getInstance().getSetupPanel().refreshPlayerList();
            }
        }
    }
    
    private static void gameState(KeyEvent e)
    {
        int key = e.getKeyCode();
        
        if (isSystemKey(key))
        {
            GameManager.pause();
        }
        
        // actie te doen bij debuggen
        else if (isDebugKey(key) && e.getID() == e.KEY_RELEASED)
        {
            DebugActionManager.startDebugActions();
        }
        
        // ga naar links
        else if (isLeftKey(key) && e.getID() == e.KEY_PRESSED)
        {
            getControlsWithLeftKey(key).getOwner().getLine().turnLeft();
        }
        
        // ga naar rechts
        else if (isRightKey(key) && e.getID() == e.KEY_PRESSED)
        {
            getControlsWithRightKey(key).getOwner().getLine().turnRight();
        }  
        
        // controls released, ga rechdoor
        else if ((isRightKey(key) || isLeftKey(key)) && e.getID() == e.KEY_RELEASED)
        {
            ControlSet r = getControlsWithLeftKey(key);
            if (r != null)
            r.getOwner().getLine().straight();

            r = getControlsWithRightKey(key);
            if (r != null)
            r.getOwner().getLine().straight();
        }
        
        // powerup!
        else if (isPowerKey(key))
        {
            getControlsWithPowerKey(key).getOwner().usePowerup();
        }
    }
    
    private static void roundFinishState(KeyEvent e)
    {
        int key = e.getKeyCode();
        
        if (isSystemKey(key))
        {
            if (ScoreManager.scoreReached())
            {
                GameManager.endGame();
            }
            else
            {
                GameManager.nextRound();
            }
        }
    }
    
    // het is belangrijk maar een enkele dispatcher te hebben, anders worden er events weggegooid
    public boolean dispatchKeyEvent(KeyEvent e)
    {        
        int key = e.getKeyCode();
        
        // escape
        if (isQuitKey(key))
            Main.quit();
        
        switch (Overview.getGameState())
        {
            case Overview.STATE_SETUP:  // het scherm waarin we spelers kiezen enzo
            {
                setupState(e);
                break;
            }

            case Overview.STATE_INGAME:  // tijdens het spelen
            {
                gameState(e);
                break;
            }

            case Overview.STATE_ROUND_FINISH:  // ronde klaar
            {
                roundFinishState(e);
                break;
            }

            case Overview.STATE_GAME_FINISH:
            {
                //Overview.getInstance().showSetup();
                break;
            }
        }
        return true;
    }
}
